home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d12
/
ddj0190.arc
/
SCHULMAN.LST
< prev
next >
Wrap
File List
|
1989-12-19
|
10KB
|
368 lines
_STALKING GENERAL PROTECTION FAULTS: PART I_
by Andrew Schulman
[LISTIN╟ ONE]
/¬ FFFF.C
-- causes GP fault in real mode on 286/386, and in Virtual 86 mode
-- catch it in real mode
-- can't catch it in Virtual 86 mode
Turbo C: tcc ffff.c
Microsoft C: cl ffff.c
*/
#include <stdio.h>
#include <dos.h>
#include "gpfault.h"
void (interrupt far *old)();
void fini(char *msg, int exit_code)
{
puts(msg);
_dos_setvect(INT_GPFAULT, old);
exit(exit_code);
}
void far my_exit(void) { fini("Bye!", 1); }
void interrupt far handler(REG_PARAMS r)
{
printf("\nProtection violation at %04X:%04X\n", r.cs, r.ip);
/* change CS:IP on stack so control is "returned" to my_exit */
/* this is an alternative to using longjmp() */
r.cs = FP_SEG(my_exit);
r.ip = FP_OFF(my_exit);
}
main()
{
int *p = (int *) -1;
old = _dos_getvect(INT_GPFAULT);
#ifndef CRASH_AT
_dos_setvect(INT_GPFAULT, handler);
#endif
printf("int at %p is ", p);
printf("%04X\n", *p);
/*NOTREACHED on 286/386 */
fini("Done!", 0);
}
[LISTIN╟ TWO]
/¬ GPFAULT.H
-- REG_PARAM structure represents stack at entry to interrupt handler
-- CPU pushes flags, CS:IP, and, for protected-mode INT 08-0D,
an error code
-- Compiler pushes all other registers at entry to interrupt function
-- Turbo C pushes registers in a strange order
-- Watcom C 386 7.0 also pushes FS and GS registers (unfortunately
MetaWare High C for MS-DOS 386 1.5 does not)
-- replace Microsoft C 5.1 FP_SEG, FP_OFF macros with ones that don't
requires lvalues
-- keep Watcom C 386 7.0 FP_SEG, etc. -- these work for 48-bit pointers
-- for MetaWare High C for 386 MS-DOS, need our own 48-bit FP_SEG, etc.
*/
#ifdef InstantC_16M
/* Rational Systems Instant-C/16M protected-mode C interpreter */
#define DOS16M
#define PROT_MODE
#endif
typedef struct {
#if defined(__WATCOMC__) && defined(__386__)
unsigned gs,fs;
#endif
#ifdef __TURBOC__
unsigned bp,di,si,ds,es,dx,cx,bx,ax;
#else
unsigned es,ds,di,si,bp,sp,bx,dx,cx,ax; /* same as PUSHA */
#endif
#ifdef PROT_MODE
unsigned err_code; /* for pmode INT 08-0D */
#endif
unsigned ip,cs,flags;
} REG_PARAMS;
#ifdef __TURBOC__
#define _dos_setvect(x,y) setvect(x,y)
#define _dos_getvect(x) getvect(x)
#endif
#define INT_GPFAULT 0x0D
/* 386 protected-mode: far pointer is 48 bits; near pointer is 32 bits */
/* thus, 386 pmode near pointer can hold a real-mode far pointer */
#ifdef __HIGHC__
#define real_far _near
#define prot_far _far
#define far _far
#else
#if defined(__WATCOMC__) && defined(__386__)
#define real_far near
#define prot_far far
#endif
#endifè
#ifdef __HIGHC__
/* use overlay struct: no High C support for 48-bit immediate values */
/* remember that unsigned is 32 bits, short is 16 bits */
typedef struct { unsigned off; short seg; } overlay;
#define FP_SEG(fp) ((overlay prot_far *) &(fp))->seg
#define FP_OFF(fp) ((overlay prot_far *) &(fp))->off
#else
#if (!(defined(__WATCOMC__) && defined(__386__)))
/* Microsoft C FP_SEG() and FP_OFF() require an lvalue: yuk! */
#ifdef FP_SEG
#undef FP_SEG
#undef MK_FP
#undef FP_OFF
#endif
#define FP_SEG(fp) (((UL)(fp)) >> 16)
#define MK_FP(seg,off) ((FP)(UL)(((UL)(seg) << 16) | (off)))
#define FP_OFF(fp) ((unsigned)(fp))
#endif
#endif
typedef unsigned long UL;
typedef void far *FP;
typedef enum { FALSE, TRUE } BOOL;
#ifdef __HIGHC__
#pragma Calling_convention(C_interrupt | _FAR_CALL);
typedef void (*IPROC)();
#pragma Calling_convention();
#else
typedef void (interrupt far *IPROC)();
#endif
[LISTIN╟ THREE]
/¬ GPFAULT.C -- for AI Architects OS/286 or Rational Systems DOS/16M
for AI Architects:
cl -AL -Ox -Gs2 -c -DPROT_MODE gpfault.c
link gpfault,gpfault,gpfault/map,\os286\llibce;
\os286\express gpfault
cp gpfault
for DOS16M:
if not exist dos16lib.obj cl -AL -Ox -Gs2 -c source\dos16lib.c
cl -AL -Ox -Gs2 -c -DPROT_MODE -DDOS16M -Zi gpfault.c
link /co preload crt0_16m pml gpfault dos16lib /noe,gpfault;
makepm gpfault
splice gpfault gpfault
d gpfault
*/
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <string.h>
#include <dos.h>
#ifdef DOS16M
#include "dos16.h"
#endif
#include "gpfault.h"
#define IN_MY_CODE 11593
#define IN_USER_CODE 16843
#define IN_HANDLER 40311
unsigned whereami = IN_MY_CODE; /* need our own protection for this */
jmp_buf toplevel;
jmp_buf toplevel_copy = {0}; /* initialized, in a different segment */
unsigned legal = 0; /* just a legal address to bang on */
void (interrupt far *old_int13handler)();
void interrupt far int13handler(REG_PARAMS r); /* GP fault handler */
void goto_toplevel(void); /* longjump out of handler */
void revert(void); /* restore default handler */
void fail(char *msg, FP fp); /* fail by calling default handler */
main(int argc, char *argv[])
{
char buf[255];
unsigned far *fp;
unsigned data;
old_int13handler = _dos_getvect(INT_GPFAULT);
_dos_setvect(INT_GPFAULT, int13handler);
printf("'Q' to quit, '!' to reinstall default GP Fault handler\n");
printf("%Fp is a legal address to poke\n", &legal);
/* next line helps illustrate limitations of protection */
printf("%Fp is not a legal address to poke\n", &legal-1);
setjmp(toplevel);
whereami = IN_MY_CODE;
memcpy(toplevel_copy, toplevel, sizeof(jmp_buf));
for (;;)
{
printf("$ ");
*buf = '\0';
gets(buf);
if (toupper(*buf) == 'Q')
break;
else if (*buf == '!')
{
revert();
continue;
}
sscanf(buf, "%Fp %u", &fp, &data);
whereami = IN_USER_CODE;
*fp = data; /* the crucial line of code */
printf("poked %Fp with %u\n", fp, *fp);
whereami = IN_MY_CODE;
}
revert();
puts("Bye");
return 0;
}
void revert(void)
{
_dos_setvect(INT_GPFAULT, old_int13handler);
}
void fail(char *msg, FP fp)
{
(fp) ? printf(msg, fp) : puts(msg);
revert();
_chain_intr(old_int13handler);
}
void goto_toplevel(void)
{
if (memcmp(toplevel, toplevel_copy, sizeof(jmp_buf)) == 0)
longjmp(toplevel, -1);
else
fail("Toplevel context has been trompled", 0);
}
void interrupt far int13handler(REG_PARAMS r)
{
switch (whereami)
{
case IN_HANDLER:
fail("\nDouble fault at %Fp\n", MK_FP(r.cs, r.ip));
/*NOTREACHED*/
case IN_MY_CODE:
fail("\nInternal error at %Fp\n", MK_FP(r.cs, r.ip));
/*NOTREACHED*/
case IN_USER_CODE:
whereami = IN_HANDLER;
_enable(); /* reenable interrupts */
/* we could use Intel LAR and LSL instructions here to
figure out why GP fault took place: did we try to write
into code? or did offset overrun segment limit? */
printf("\nProtection violation at %04X:%04X\n", r.cs, r.ip);
if (r.err_code)
printf("Error code %04X\n", r.err_code);
printf("<ES %04X> <DS %04X> <DI %04X> <SI %04X>\n",
r.es, r.ds, r.di, r.si);
printf("<AX %04X> <BX %04X> <CX %04X> <DX %04X>\n",
r.ax, r.bx, r.cx, r.dx);
goto_toplevel();
/*NOTREACHED*/
default:
whereami = IN_HANDLER;
_enable();
puts("whereami flag got trompled");
goto_toplevel();
/*NOTREACHED*/
}
}
#ifdef DOS16M
void _dos_setvect(unsigned intno, IPROC isr)
{
D16pmInstall(intno, FP_SEG(isr), FP_OFF(isr), NULL);
}
IPROC _dos_getvect(unsigned intno)
{
IPROC isr;
D16pmGetVector(intno, (INTVECT *) &isr);
return isr;
}
#endif
Examplσ 1║ Thi≤ codσ wil∞ causσ ß G╨ faul⌠ iε protecteΣ modσ
main()
{
int far *fp = (int far *) main;
*fp = rand();
main();
}
Examplσ 2║ Iµ thi≤ prograφ G╨ faults¼ it'≤ becausσ oµ aε erro≥ b∙ ì
thσ user¼ no⌠ b∙ thσ applicatioε itself.
main(int argc, char *argv[])
{
int far *fp = (int far *) atol(argv[1]);
*fp = atoi(argv[2]);
}
Figurσ 1║ ┴ G╨ faul⌠ dump
Session Title: UR/Forth
SYS1943: A program caused a protection violation.
TRAP 000D
AX=2092 BX=0000 CX=FFFF DX=3FC2 BP=FFFA
SI=05EA DI=05E4 DS=00C7 ES=0000 FLG=2206
CS=0227 IP=2093 SS=00C7 SP=FBFC MSW=FFED
CSLIM=FFFE SSLIM=FFFF DSLIM=FFFF ESLIM=****
CSACC=DF SSACC=F3 DSACC=F3 ESACC=**
ERRCD=0000 ERLIM=**** ERACC=**
End the program
Figurσ 2║ ┴ GPFAULT.EX╨ session
C:\DOS16M>gpfault
DOS/16M Protected Mode Run-Time Version 3.25
Copyright (C) 1987,1988,1989 by Rational Systems, Inc.
'Q' to quit, '!' to reinstall default GP fault handler
00A0:04C6 is a legal address to poke
00A0:04C4 is not a legal address to poke
$ 1234:5678 666
Protection violation at 0088:00C5!
Error code 1234
<ES 00A0> <DS 00A0> <DI 1AC0> <SI 0082>
<AX 0015> <BX 0BF8> <CX 0015> <DX 0000>
$ 00A0:04C4 666
poked 00A0:04C4 with 666
$ 00A0:04C2 1
poked 00A0:04C2 with 1
$ 0088:00C5 666
Protection violation at 0088:00CB!
<ES 0088> <DS 00A0> <DI 1AC0> <SI 0082>
<AX 029A> <BX 00CB> <CX 0015> <DX 0000>
$ 0:0 0
Protection violation at 0088:00CB!
<ES 0000> <DS 00A0> <DI 1AC0> <SI 0082>
<AX 0000> <BX 0000> <CX 0015> <DX 0000>
$ !
$ 0:0 0
DOS/16M: Unexpected Interrupt=000D at 0088:00CB
code=0000 ss=00A0 ds=00A0 es=0000
ax=0000 bx=0000 cx=0015 dx=0000 sp=1982 bp=1A92 si=0082 di=1AC0
C:\DOS16M>